package com.funeral.util;

import com.funeral.exception.CallException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * 用来简化操作HttpClient的工具类 <br>
 * Created by 陪葬品 on 2017/7/6.
 */
public class HttpClientUtils {
    /**
     * 执行请求
     * @param httpRequest
     * @return
     * @throws CallException
     */
    public static HttpResponse execute(HttpUriRequest httpRequest) throws CallException{
        HttpClient client = HttpClients.createDefault();
        HttpResponse result = null;
        try {
            result = client.execute(httpRequest);
        }catch (IOException ioe){
            ioe.printStackTrace();
            throw new CallException("Execute Error:"+ioe.getMessage());
        }
        return result;
    }

    /**
     * 批量异步执行Http请求
     * @param httpUriRequests
     * @return
     * @throws CallException
     */
    public static Map<HttpUriRequest,HttpResponse> executeAsync(Collection<HttpUriRequest> httpUriRequests) throws CallException{

        ConnectingIOReactor ioReactor = null;
        try {
            ioReactor = new DefaultConnectingIOReactor();
        } catch (IOReactorException e) {
            throw new CallException(e);
        }
        PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
        cm.setMaxTotal(50);
        CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom().setConnectionManager(cm).build();
        httpAsyncClient.start();
        final Map<HttpUriRequest,HttpResponse> result = new ConcurrentHashMap<HttpUriRequest, HttpResponse>();
        final CountDownLatch latch = new CountDownLatch(httpUriRequests.size());
        for(final HttpUriRequest httpUriRequest:httpUriRequests){
            httpAsyncClient.execute(httpUriRequest, new FutureCallback<HttpResponse>() {
                public void completed(HttpResponse httpResponse) {
                    latch.countDown();
                    result.put(httpUriRequest,httpResponse);
                }

                public void failed(Exception e) {
                    latch.countDown();
                    result.put(httpUriRequest,null);
                    e.printStackTrace();
                }

                public void cancelled() {
                    latch.countDown();
                    result.put(httpUriRequest,null);
                }
            });
        }
        try {
            latch.await();
            httpAsyncClient.close();
        } catch (InterruptedException e) {
            throw new CallException(e);
        } catch (IOException e) {
            throw new CallException(e);
        }

        return result;
    }

    /**
     * 为get请求的URL添加参数
     * @param url
     * @param params
     * @return
     */
    public static String addParamForGET(String url, Map<String,String> params) throws CallException {
        if(url == null){
            return "";
        }
        if(params == null || params.isEmpty()){
            return url;
        }
        StringBuffer sb = new StringBuffer(url);
        String tmp = "";

        if(url.indexOf("?")==-1){
            sb.append("?");
        }else{
            tmp = "&";
        }
        for(Map.Entry<String,String> entry:params.entrySet()){
            sb.append(tmp);
            sb.append(entry.getKey());sb.append("=");
            try {
                sb.append(URLEncoder.encode(entry.getValue()==null?"null":entry.getValue(),"utf-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new CallException("URLEncode转换失败"+e.getMessage());
            }
            tmp="&";
        }
        return sb.toString();
    }

    /**
     * 为POST请求的HttpPost类添加参数
     * @param post
     * @param params
     * @throws UnsupportedEncodingException
     */
    public static void addParamForPost(HttpPost post, Map<String,String> params) throws CallException {
        if(post == null){return;}
        if(params == null || params.isEmpty()){return;}
        List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
        for(Map.Entry<String,String> entry:params.entrySet()){
            list.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));  //请求参数
        }
        UrlEncodedFormEntity entity = null;
        try {
            entity = new UrlEncodedFormEntity(list,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new CallException("URLEncode转换失败"+e.getMessage());
        }
        post.setEntity(entity); //post设置请求参数
    }

    /**
     * 为HttpRequest添加请求头
     * @param httpRequest
     * @param headers
     * @throws CallException
     */
    public static void addHeaders(HttpRequest httpRequest, Map<String, String> headers) throws CallException{
        if(headers == null ){
            throw new CallException("设置请求头失败：HttpRequest 为 null!");
        }
        if(headers.isEmpty()){return;}
        for(Map.Entry<String,String> entry:headers.entrySet() ){
            httpRequest.setHeader(entry.getKey(),entry.getValue());
        }
    }

    /**
     * 从HttpResponse提取简易信息
     * @param response
     * @return
     * @throws CallException
     */
    public static String simpleResult(HttpResponse response)throws CallException{
        if(response == null){
            throw new CallException("response is blank!");
        }
        try {
            return EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            throw new CallException(e);
        }

    }
}
